﻿
@{
    Layout = null;
    //选中的部门
    string fid = ViewBag.Fid;
    //显示类型：部门经理、部门负责人
    string type = ViewBag.Type ?? "managerName";

    string showName = "";
    if (type == "directorName")
    {
        showName = _multiLangService.GetOrAndMultiLangValue(Fap.Core.MultiLanguage.MultiLanguageOriginEnum.Page, "director", "负责人");
    }
    else if (type == "managerName")
    {
        showName = _multiLangService.GetOrAndMultiLangValue(Fap.Core.MultiLanguage.MultiLanguageOriginEnum.Page, "manager", "经理");
    }
}

<!DOCTYPE html>
<html>
<head>
    <title>组织架构图</title> <!--[if !IE]> -->
    <script type="text/javascript">
        window.jQuery || document.write("<script src='@Url.Content("~/Content/js/jquery.js")'>" + "<" + "/script>");
    </script>

    <!-- <![endif]-->
    <!--[if IE]>
    <script type="text/javascript">
     window.jQuery || document.write("<script src='@Url.Content("~/Content/js/jquery1x.js")'>"+"<"+"/script>");
    </script>
    <![endif]-->
    <script src="~/Content/layer/layer.js"></script>
    <script src="~/Scripts/Fap/common.js?v=1"></script>
    <script src="~/Content/js/lodash.min.js"></script>
    <!-- Sets the basepath for the library if not in same directory -->
    <script type="text/javascript">mxBasePath = '/Content/mxGraph/src';</script>
    <!-- Loads and initializes the library -->
    <script src="~/Content/mxGraph/mxClient.js"></script>
    <script type="text/javascript">
        /*
            Defines a custom shape for the tree node that includes the
            upper half of the outgoing edge(s).
        */
        function TreeNodeShape() { };

        TreeNodeShape.prototype = new mxCylinder();
        TreeNodeShape.prototype.constructor = TreeNodeShape;

        // Defines the length of the upper edge segment.
        TreeNodeShape.prototype.segment = 0;

        // Needs access to the cell state for rendering
        TreeNodeShape.prototype.apply = function (state) {
            mxCylinder.prototype.apply.apply(this, arguments);
            this.state = state;
        };

        TreeNodeShape.prototype.redrawPath = function (path, x, y, w, h, isForeground) {
            var graph = this.state.view.graph;
            var hasChildren = graph.model.getOutgoingEdges(this.state.cell).length > 0;

            if (isForeground) {
                if (hasChildren) {
                    // Painting outside of vertex bounds is used here
                    path.moveTo(w / 2, h + this.segment);
                    path.lineTo(w / 2, h);
                    path.end();
                }
            }
            else {
                path.moveTo(0, 0);
                path.lineTo(w, 0);
                path.lineTo(w, h);
                path.lineTo(0, h);
                path.close();
            }
        };

        mxCellRenderer.registerShape('treenode', TreeNodeShape);

        // Defines a custom perimeter for the nodes in the tree
        mxGraphView.prototype.updateFloatingTerminalPoint = function (edge, start, end, source) {
            var pt = null;

            if (source) {
                pt = new mxPoint(start.x + start.width / 2,
                    start.y + start.height + TreeNodeShape.prototype.segment);
            }
            else {
                pt = new mxPoint(start.x + start.width / 2, start.y);
            }

            edge.setAbsoluteTerminalPoint(pt, source);
        };
    </script>

    <!-- Example code -->
    <script type="text/javascript">
        // Makes the shadow brighter
        mxConstants.SHADOWCOLOR = '#C0C0C0';

        // Program starts here. Creates a sample graph in the
        // DOM node with the specified ID. This function is invoked
        // from the onLoad event handler of the document (see below).
        function main() {
            // Checks if browser is supported
            if (!mxClient.isBrowserSupported()) {
                // Displays an error message if the browser is
                // not supported.
                mxUtils.error('Browser is not supported!', 200, false);
            }
            else {
                //mxGraph.prototype.collapsedImage = new mxImage(mxClient.imageBasePath + '/collapsed.gif', 9, 9);
                //mxGraph.prototype.expandedImage = new mxImage(mxClient.imageBasePath + '/expanded.gif', 9, 9);
                // Workaround for Internet Explorer ignoring certain styles
                var container = document.createElement('div');
                container.style.position = 'absolute';
                container.style.overflow = 'hidden';
                container.style.left = '0px';
                container.style.top = '0px';
                container.style.right = '0px';
                container.style.bottom = '0px';
                container.style.background = 'url("/images/orgchart/wires-grid.gif")';
                container.style.backgroundPosition = '-1px 0px';
                var outline = document.getElementById('outlineContainer');

                mxEvent.disableContextMenu(container);

                if (mxClient.IS_QUIRKS) {
                    document.body.style.overflow = 'hidden';
                    new mxDivResizer(container);
                    new mxDivResizer(outline);
                }

                // Sets a gradient background
                //if (mxClient.IS_GC || mxClient.IS_SF) {
                //    container.style.background = '-webkit-gradient(linear, 0% 0%, 0% 100%, from(#FFFFFF), to(#E7E7E7))';
                //}
                //else if (mxClient.IS_NS) {
                //    container.style.background = '-moz-linear-gradient(top, #FFFFFF, #E7E7E7)';
                //}
                //else if (mxClient.IS_IE) {
                //    container.style.filter = 'progid:DXImageTransform.Microsoft.Gradient(' +
                //        'StartColorStr=\'#FFFFFF\', EndColorStr=\'#E7E7E7\', GradientType=0)';
                //}

                document.body.appendChild(container);

                // Creates the graph inside the given container
                var graph = new mxGraph(container);
                // Avoids overlap of edges and collapse icons重要的一句
                graph.keepEdgesInBackground = true;
                // Enables automatic sizing for vertices after editing and
                // panning by using the left mouse button.
                graph.setCellsMovable(false);
                graph.setAutoSizeCells(true);
                graph.setPanning(true);
                graph.centerZoom = false;
                graph.panningHandler.useLeftButtonForPanning = true;

                // Displays a popupmenu when the user clicks
                // on a cell (using the left mouse button) but
                // do not select the cell when the popup menu
                // is displayed
                graph.panningHandler.popupMenuHandler = false;

                // Creates the outline (navigator, overview) for moving
                // around the graph in the top, right corner of the window.
                var outln = new mxOutline(graph, outline);

                // Disables tooltips on touch devices
                graph.setTooltips(!mxClient.IS_TOUCH);

                // Set some stylesheet options for the visual appearance of vertices
                var style = graph.getStylesheet().getDefaultVertexStyle();
                style[mxConstants.STYLE_SHAPE] = 'label';

                style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
                style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT;
                style[mxConstants.STYLE_SPACING_LEFT] = 54;

                style[mxConstants.STYLE_GRADIENTCOLOR] = '#A9C4EB';
                style[mxConstants.STYLE_STROKECOLOR] = '#7EA6E0';
                style[mxConstants.STYLE_FILLCOLOR] = '#ffffff';

                style[mxConstants.STYLE_FONTCOLOR] = '#1d258f';
                style[mxConstants.STYLE_FONTFAMILY] = 'Microsoft YaHei';
                style[mxConstants.STYLE_FONTSIZE] = '14';
                style[mxConstants.STYLE_FONTSTYLE] = '1';

                style[mxConstants.STYLE_SHADOW] = '1';
                style[mxConstants.STYLE_ROUNDED] = '1';
                style[mxConstants.STYLE_GLASS] = '0';
                style["arcSize"] = 10;

                style[mxConstants.STYLE_IMAGE] = '/Content/avatars/avatar.png';
                style[mxConstants.STYLE_IMAGE_WIDTH] = '48';
                style[mxConstants.STYLE_IMAGE_HEIGHT] = '48';
                style[mxConstants.STYLE_SPACING] = 8;

                // Sets the default style for edges
                style = graph.getStylesheet().getDefaultEdgeStyle();
                style[mxConstants.STYLE_ROUNDED] = true;
                style[mxConstants.STYLE_STROKEWIDTH] = 2;
                style[mxConstants.STYLE_EXIT_X] = 0.5; // center
                style[mxConstants.STYLE_EXIT_Y] = 1.0; // bottom
                style[mxConstants.STYLE_EXIT_PERIMETER] = 0; // disabled
                style[mxConstants.STYLE_ENTRY_X] = 0.5; // center
                style[mxConstants.STYLE_ENTRY_Y] = 0; // top
                style[mxConstants.STYLE_ENTRY_PERIMETER] = 0; // disabled

                // Disable the following for straight lines
                style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom;

                // Stops editing on enter or escape keypress
                var keyHandler = new mxKeyHandler(graph);

                // Enables automatic layout on the graph and installs
                // a tree layout for all groups who's children are
                // being changed, added or removed.
                var layout = new mxCompactTreeLayout(graph, false);
                layout.useBoundingBox = false;
                layout.edgeRouting = false;
                layout.levelDistance = 60;
                layout.nodeDistance = 16;

                // Allows the layout to move cells even though cells
                // aren't movable in the graph
                layout.isVertexMovable = function (cell) {
                    return true;
                };

                var layoutMgr = new mxLayoutManager(graph);

                layoutMgr.getLayout = function (cell) {
                    if (cell.getChildCount() > 0) {
                        return layout;
                    }
                };
                // Disallow any selections
                graph.setCellsSelectable(false);

                // Defines the condition for showing the folding icon
                graph.isCellFoldable = function (cell) {
                    return this.model.getOutgoingEdges(cell).length > 0;
                };

                // Defines the position of the folding icon
                graph.cellRenderer.getControlBounds = function (state) {
                    if (state.control != null) {
                        var oldScale = state.control.scale;
                        var w = state.control.bounds.width / oldScale;
                        var h = state.control.bounds.height / oldScale;
                        var s = state.view.scale;

                        return new mxRectangle(state.x + state.width / 2 - w / 2 * s,
                            state.y + state.height + TreeNodeShape.prototype.segment * s - h / 2 * s,
                            w * s, h * s);
                    }

                    return null;
                };

                // Implements the click on a folding icon
                graph.foldCells = function (collapse, recurse, cells) {
                    this.model.beginUpdate();
                    try {
                        toggleSubtree(this, cells[0], !collapse);
                        this.model.setCollapsed(cells[0], collapse);

                        // Executes the layout for the new graph since
                        // changes to visiblity and collapsed state do
                        // not trigger a layout in the current manager.
                        layout.execute(graph.getDefaultParent());
                    }
                    finally {
                        this.model.endUpdate();
                    }
                };


                // Fix for wrong preferred size
                var oldGetPreferredSizeForCell = graph.getPreferredSizeForCell;
                graph.getPreferredSizeForCell = function (cell) {
                    var result = oldGetPreferredSizeForCell.apply(this, arguments);

                    if (result != null) {
                        result.width = Math.max(120, result.width - 40);
                    }

                    return result;
                };

                // Sets the maximum text scale to 1
                graph.cellRenderer.getTextScale = function (state) {
                    return Math.min(1, state.view.scale);
                };

                // Dynamically adds text to the label as we zoom in
                // (without affecting the preferred size for new cells)
                //放大后显示多行
                graph.cellRenderer.getLabelValue = function (state) {
                    var cell = state.cell;
                    var result=cell.value;

                    if (state.view.graph.getModel().isVertex(state.cell)) {
                        if (state.view.scale > 1 && cell.manager!=null) {
                            result += '\n经理：'+cell.manager;
                        }

                        if (state.view.scale > 1.3 && cell.direct!=null) {
                            result += '\n负责人：' + cell.direct;
                        }
                        if (state.view.scale > 1.5) {
                            result += '\n人数：' + cell.num;

                        }
                    }

                    return result;
                };

                // Gets the default parent for inserting new cells. This
                // is normally the first child of the root (ie. layer 0).
                var parent = graph.getDefaultParent();
                $.get("@Url.Content("~/Organization/Api/OrgDept/OrgChartGojs/")@fid", function (nodes) {
                    if (nodes) {
                        // Adds the root vertex of the tree
                        graph.getModel().beginUpdate();
                        try {
                            var w = graph.container.offsetWidth;
                            var pnode = _.find(nodes, { key: '@fid' });
                            var photoKey = pnode.managerUid == '' ? '111' : pnode.managerUid
                            var v1 = graph.insertVertex(parent, 'treeRoot',
                                pnode.deptName, w / 2 - 30, 20, 140, 60, 'image=/Component/Photo/' + photoKey + ';');
                            v1.manager = pnode.managerName;
                            v1.direct = pnode.directorName;
                            v1.num = pnode.deptNum;
                            graph.updateCellSize(v1);
                            addOverlays(graph, v1,pnode.key, false);
                            //添加子节点
                            addChildren(graph, v1, nodes, pnode);
                        }
                        finally {
                            // Updates the display
                            graph.getModel().endUpdate();
                        }

                    }
                });


                var content = document.createElement('div');
                content.style.padding = '4px';

                var tb = new mxToolbar(content);

                tb.addItem('放大', '/images/orgchart/zoom_in32.png', function (evt) {
                    graph.zoomIn();
                });

                tb.addItem('缩小', '/images/orgchart/zoom_out32.png', function (evt) {
                    graph.zoomOut();
                });

                tb.addItem('实际尺寸', '/images/orgchart/view_1_132.png', function (evt) {
                    graph.zoomActual();
                });

                tb.addItem('打印', '/images/orgchart/print32.png', function (evt) {
                    var preview = new mxPrintPreview(graph, 1);
                    preview.open();
                });

                tb.addItem('海报打印', '/images/orgchart/press32.png', function (evt) {
                    var pageCount = mxUtils.prompt('输入最大页数', '1');

                    if (pageCount != null) {
                        var scale = mxUtils.getScaleForPageCount(pageCount, graph);
                        var preview = new mxPrintPreview(graph, scale);
                        preview.open();
                    }
                });

                wnd = new mxWindow('工具', content, 0, 0, 200, 66, false);
                wnd.setMaximizable(false);
                wnd.setScrollable(false);
                wnd.setResizable(false);
                wnd.setVisible(true);
            }
        };

        function addChildren(graph, cell,nodes, pnode) {
            var cnodes = _.filter(nodes, function (o) { return o.parent == pnode.key; });
            var model = graph.getModel();
            var parent = graph.getDefaultParent();
            var vertex;

            model.beginUpdate();
            try {
                _.each(cnodes, function (node) {
                    vertex = graph.insertVertex(parent, null, node.deptName);
                    var geometry = model.getGeometry(vertex);

                    vertex.manager = node.managerName;
                    vertex.direct = node.directorName;
                    vertex.num = node.deptNum;
                    // Updates the geometry of the vertex with the
                    // preferred size computed in the graph
                    var size = graph.getPreferredSizeForCell(vertex);
                    geometry.width = size.width;
                    geometry.height = size.height;
                    var photoKey = node.managerUid == '' ? '111' : node.managerUid
                    vertex.style = 'image=/Component/Photo/' + photoKey+ ';';
                    // Adds the edge between the existing cell
                    // and the new vertex and executes the
                    // automatic layout on the parent
                    var edge = graph.insertEdge(parent, null, '', cell, vertex);

                    // Configures the edge label "in-place" to reside
                    // at the end of the edge (x = 1) and with an offset
                    // of 20 pixels in negative, vertical direction.
                    edge.geometry.x = 1;
                    edge.geometry.y = 0;
                    edge.geometry.offset = new mxPoint(0, -20);

                    addOverlays(graph, vertex,node.key, true);
                    addChildren(graph, vertex, nodes, node);
                });

            }
            finally {
                model.endUpdate();
            }

            return vertex;
        }
        function addOverlays(graph, cell,nodekey, addDeleteIcon) {
            //var overlay = new mxCellOverlay(new mxImage('/images/orgchart/add.png', 24, 24), '添加子部门');
            //overlay.cursor = 'hand';
            //overlay.align = mxConstants.ALIGN_CENTER;
            //overlay.addListener(mxEvent.CLICK, mxUtils.bind(this, function (sender, evt) {
            //    addChild(graph, cell);
            //}));

            //graph.addCellOverlay(cell, overlay);

            //if (addDeleteIcon) {
            //    overlay = new mxCellOverlay(new mxImage('/images/orgchart/close.png', 30, 30), '删除');
            //    overlay.cursor = 'hand';
            //    overlay.offset = new mxPoint(-4, 8);
            //    overlay.align = mxConstants.ALIGN_RIGHT;
            //    overlay.verticalAlign = mxConstants.ALIGN_TOP;
            //    overlay.addListener(mxEvent.CLICK, mxUtils.bind(this, function (sender, evt) {
            //        deleteSubtree(graph, cell);
            //    }));

            //    graph.addCellOverlay(cell, overlay);
            //}
            var overlay = new mxCellOverlay(new mxImage('/images/orgchart/link.gif', 16, 16), '钻取');
            overlay.cursor = 'hand';
            overlay.offset = new mxPoint(14, 8);
            overlay.align = mxConstants.ALIGN_LEFT;
            overlay.verticalAlign = mxConstants.ALIGN_TOP;
            overlay.addListener(mxEvent.CLICK, mxUtils.bind(this, function (sender, evt) {
                if (nodekey === '') return;
                let url = "@Url.Content("~/Organization/OrgDept/DeptEmployee/")" + nodekey;
                parent.layer.open({
                    type: 2,
                    title:"员工信息",
                    content: url,
                    area: ['800px', '600px'],
                    maxmin: true
                });               
            }));
            graph.addCellOverlay(cell, overlay);
        };

        function addChild(graph, cell) {
            var model = graph.getModel();
            var parent = graph.getDefaultParent();
            var vertex;

            model.beginUpdate();
            try {
                vertex = graph.insertVertex(parent, null, '双击设置名称');
                var geometry = model.getGeometry(vertex);

                // Updates the geometry of the vertex with the
                // preferred size computed in the graph
                var size = graph.getPreferredSizeForCell(vertex);
                geometry.width = size.width;
                geometry.height = size.height;

                // Adds the edge between the existing cell
                // and the new vertex and executes the
                // automatic layout on the parent
                var edge = graph.insertEdge(parent, null, '', cell, vertex);

                // Configures the edge label "in-place" to reside
                // at the end of the edge (x = 1) and with an offset
                // of 20 pixels in negative, vertical direction.
                edge.geometry.x = 1;
                edge.geometry.y = 0;
                edge.geometry.offset = new mxPoint(0, -20);

                addOverlays(graph, vertex,'', true);
            }
            finally {
                model.endUpdate();
            }

            return vertex;
        };

        function deleteSubtree(graph, cell) {
            // Gets the subtree from cell downwards
            var cells = [];
            graph.traverse(cell, true, function (vertex) {
                cells.push(vertex);

                return true;
            });

            graph.removeCells(cells);
        };
        // Updates the visible state of a given subtree taking into
        // account the collapsed state of the traversed branches
        function toggleSubtree(graph, cell, show) {
            show = (show != null) ? show : true;
            var cells = [];

            graph.traverse(cell, true, function (vertex) {
                if (vertex != cell) {
                    cells.push(vertex);
                }

                // Stops recursion if a collapsed cell is seen
                return vertex == cell || !graph.isCellCollapsed(vertex);
            });

            graph.toggleCells(show, cells, true);
        };
    </script>
</head>
<!-- Calls the main function after the page has loaded. Container is dynamically created. -->
<body onload="main();">
    <!-- Creates a container for the outline -->
    <div id="outlineContainer"
         style="z-index:1;position:absolute;overflow:hidden;top:0px;right:0px;width:160px;height:120px;background: #ffffff;cursor:crosshair;border-style:solid;border-color:lightgray;">
    </div>

</body>
</html>
